package com.wyk.session;

import com.wyk.config.Function;
import com.wyk.config.dataSourceConfiguration;
import com.wyk.config.mapperBean;
import org.apache.commons.dbcp2.BasicDataSource;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;


/**
 * @ClassName: wykConfiguration
 * @Description: //todo TODO 读取与解析配置信息，并返回处理后的Environment
 * @Author: 初久
 * @Date: 2022/7/13 9:35
 **/
public class wykConfiguration extends dataSourceConfiguration {

    private static final ClassLoader classLoader = ClassLoader.getSystemClassLoader();

    /**
     * @return java.sql.Connection
     * @Description //TODO 利用dom4j读取xml信息并处理
     * @Param [java.lang.String]
     * @Date 10:00 2022/7/13
     **/
    public Connection loadXml(String resource) {
        try {
            Element root = createRootElement(resource);
            return evalDataSource(root);
        } catch (Exception e) {
            throw new RuntimeException("读取xml配置文件失败！ ：" + resource);
        }
    }

    /**
     * @return java.sql.Connection【数据库连接】
     * @Description //TODO 获取数据库连接的必要信息
     * @Param [org.dom4j.Element]
     * @Date 10:00 2022/7/13
     **/
    private Connection evalDataSource(Element node) throws ClassNotFoundException {

        parseConfiguration(node);

        return getConnection();
    }

    /**
     * @return java.sql.Connection【数据库连接】
     * @Description //TODO 建立数据库连接
     * @Param [org.dom4j.Element]
     * @Date 10:00 2022/7/13
     **/
    private Connection getConnection() throws ClassNotFoundException {
        BasicDataSource dataSource = this.getDataSource();
        Class.forName(dataSource.getDriverClassName());
        Connection connection;
        try {
            //建立数据库链接
            connection = DriverManager.getConnection(dataSource.getUrl(), dataSource.getUsername(), dataSource.getPassword());
        } catch (SQLException e) {
            throw new RuntimeException("建立数据库连接失败");
        }
        return connection;
    }

    /**
     * @return com.wyk.config.mapperBean
     * @Description //TODO 读取mapper文件
     * @Param [java.lang.String]
     * @Date 13:32 2022/7/13
     **/
    public mapperBean readMapper(String path) {
        // 有就直接拿
        Map<String, mapperBean> mapperBeanMap = this.getMapperBeanMap();
        if (mapperBeanMap.containsKey(path)) {
            return mapperBeanMap.get(path);
        }

        // 没有就创建
        mapperBean mapper = createMapperBean(path);

        //添加入mapperBeanMap集合中
        mapperBeanMap.put(path, mapper);
        return mapper;
    }

    private mapperBean createMapperBean(String path) {
        mapperBean mapper = new mapperBean();
        try {
            Element root = createRootElement(path);

            mapper.setInterfaceName(root.attributeValue("namespace").trim());
            List<Function> list = new ArrayList<>(); //用来存储方法的List

            //遍历根节点下所有子节点，获取所有sql语句的信息
            Iterator rootIter = root.elementIterator();
            while (rootIter.hasNext()) {
                Function fun = new Function();    //用来存储一条sql语句（方法）的信息
                Element e = (Element) rootIter.next();

                String sqlType = e.getName().trim();
                String funcName = e.attributeValue("id").trim();
                String sql = e.getText().trim();

                fun.setSqlType(sqlType);
                fun.setFuncName(funcName);
                fun.setSql(sql);

                // insert语句返回值类型为null
                String resultType = e.attributeValue("resultType");
                if (resultType != null) {

                    Object newInstance;
                    try {
                        newInstance = Class.forName(resultType.trim()).newInstance();
                    } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e1) {
                        throw new RuntimeException("返回对象实例化失败");
                    }
                    fun.setResultType(newInstance);
                } else {
                    fun.setResultType(null);
                }

                list.add(fun);
            }
            mapper.setFunctionList(list);

        } catch (DocumentException e) {
            throw new RuntimeException("读取mapper文件失败");
        }
        return mapper;
    }

    /**
     * @return void
     * @Description //TODO 解析config.xml文件中的configuration标签
     * @Param [root]
     * @Date 23:08 2022/7/15
     **/
    private void parseConfiguration(Element root) {

        Element environments = root.element("environments");
        parseEnvironments(environments);
    }

    /**
     * @return void
     * @Description //TODO 解析configuration标签下的environments标签
     * @Param [environments]
     * @Date 23:09 2022/7/15
     **/
    private void parseEnvironments(Element environments) {
        String aDefault = environments.attributeValue("default");
        List<Element> elements = environments.elements();
        for (Element element : elements) {
            String id = element.attributeValue("id");
            if (aDefault.equals(id)) {
                parseDataSource(element.element("dataSource"));
            }
        }

    }

    /**
     * @return void
     * @Description //TODO 解析特定的environment标签:默认是dev
     * @Param [dataSource]
     * @Date 23:09 2022/7/15
     **/
    private void parseDataSource(Element dataSource) {
        BasicDataSource ds = new BasicDataSource();

        Properties properties = parseProperties(dataSource);

        ds.setDriverClassName(properties.getProperty("driver"));
        ds.setUrl(properties.getProperty("url"));
        ds.setUsername(properties.getProperty("username"));
        ds.setPassword(properties.getProperty("password"));

        this.setDataSource(ds);
    }

    /**
     * @return java.util.Properties
     * @Description //TODO 解析dataSource标签下的四个必要属性：driver、url、username、password
     * @Param [dataSource]
     * @Date 23:10 2022/7/15
     **/
    private Properties parseProperties(Element dataSource) {
        Properties properties = new Properties();
        List<Element> propertiesList = dataSource.elements("property");
        for (Element property : propertiesList) {
            properties.put(property.attributeValue("name"), property.attributeValue("value"));
        }

        return properties;
    }

    public Element createRootElement(String path) throws DocumentException {
        InputStream stream = classLoader.getResourceAsStream(path);
        SAXReader reader = new SAXReader();
        // todo 通过reader对象加载文件，获得document对象
        Document document = reader.read(stream);
        // todo 根据document对象获取根节点并返回
        return document.getRootElement();
    }

}